#include "doorbell_sound.h"

static void doorbell_sound_i2c_init()
{
    i2c_config_t i2c_cfg = {
        .mode = I2C_MODE_MASTER,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .sda_io_num = I2C_SDA_PIN,
        .scl_io_num = I2C_SCL_PIN,
        .master.clk_speed = 100000,
    };
    ESP_ERROR_CHECK(i2c_param_config(I2C_PORT, &i2c_cfg));
    ESP_ERROR_CHECK(i2c_driver_install(I2C_PORT, i2c_cfg.mode, 0, 0, 0));
}

static void doorbell_sound_i2s_init(i2s_chan_handle_t *tx_handle, i2s_chan_handle_t *rx_handle)
{
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_PORT, I2S_ROLE_MASTER);
    chan_cfg.auto_clear = 1;
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(I2S_SAMPLE_RATE),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_SAMPLE_BITS, I2S_CHANNELS),
        .gpio_cfg = {
            .mclk = I2S_MCLK_PIN,
            .bclk = I2S_BCLK_PIN,
            .ws = I2S_WS_PIN,
            .dout = I2S_DO_PIN,
            .din = I2S_DI_PIN,
        },
    };

    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, tx_handle, rx_handle));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(*tx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(*rx_handle, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_enable(*tx_handle));
    ESP_ERROR_CHECK(i2s_channel_enable(*rx_handle));
}


static void doorbell_sound_codec_init(esp_codec_dev_handle_t *codec_dev, i2s_chan_handle_t tx_handle, i2s_chan_handle_t rx_handle)
{
    audio_codec_i2s_cfg_t i2s_cfg = {
        .port = I2S_PORT,
        .rx_handle = rx_handle,
        .tx_handle = tx_handle,
    };
    const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg);
    assert(data_if);

    audio_codec_i2c_cfg_t i2c_cfg = {
        .port = I2C_PORT,
        .addr = ES8311_CODEC_DEFAULT_ADDR
    };
    const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);
    assert(out_ctrl_if);
    const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();
    assert(gpio_if);

    es8311_codec_cfg_t es8311_cfg = {
        .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH,
        .ctrl_if = out_ctrl_if,
        .gpio_if = gpio_if,
        .pa_pin = PA_PIN,
        .pa_reverted = false,
        .master_mode = false,
        .use_mclk = true,
        .digital_mic = false,
        // .no_dac_ref = true,
        .mclk_div = I2S_MCLK_MULTIPLE_256,
    };
    const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);
    assert(out_codec_if);

    esp_codec_dev_cfg_t dev_cfg = {
        .codec_if = out_codec_if,          // es8311_codec_new 获取到的接口实现
        .data_if = data_if,                    // audio_codec_new_i2s_data 获取到的数据接口实现
        .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT, // 设备同时支持录制和播放
    };
    *codec_dev = esp_codec_dev_new(&dev_cfg);
    assert(*codec_dev);
    ESP_ERROR_CHECK(esp_codec_dev_set_out_vol(*codec_dev, I2S_VOLUME));
    ESP_ERROR_CHECK(esp_codec_dev_set_in_gain(*codec_dev, I2S_GAIN));
}

void doorbell_sound_init(doorbell_sound_handle_t *handle, RingbufHandle_t mic_buffer, RingbufHandle_t speaker_buffer)
{
    doorbell_sound_handle_t temp = malloc(sizeof(doorbell_sound_t));
    assert(temp);   // 判空
    *handle = temp;
    temp->mic_buffer = mic_buffer;
    temp->speaker_buffer = speaker_buffer;
    i2s_chan_handle_t tx_handle = NULL, rx_handle = NULL;
    // 初始化I2C
    doorbell_sound_i2c_init();
    // 初始化I2S
    doorbell_sound_i2s_init(&tx_handle, &rx_handle);
    // 初始化音频设备
    doorbell_sound_codec_init(&temp->codec_dev, tx_handle, rx_handle);
}

static void doorbell_sound_mic_task(void *arg)
{
    doorbell_sound_handle_t sound = (doorbell_sound_handle_t)arg;
    void *buf = NULL;
    // 读取mic的数据，放入环形缓冲区
    while (1)
    {
        assert(xRingbufferSendAcquire(sound->mic_buffer, &buf, BUFLEN, portMAX_DELAY) == pdTRUE);
        ESP_ERROR_CHECK(esp_codec_dev_read(sound->codec_dev, buf, BUFLEN));
        assert(xRingbufferSendComplete(sound->mic_buffer, buf) == pdTRUE);
    }    
}

static void doorbell_sound_speaker_task(void *arg)
{
    doorbell_sound_handle_t sound = (doorbell_sound_handle_t)arg;
    void *buf = NULL;
    size_t buf_len = 0;
    // 从环形缓冲区读取数据，播放
    while (1)
    {
        buf = xRingbufferReceive(sound->speaker_buffer, &buf_len, portMAX_DELAY);
        if (buf)
        {
            ESP_ERROR_CHECK(esp_codec_dev_write(sound->codec_dev, buf, (int)buf_len));
            vRingbufferReturnItem(sound->speaker_buffer, buf);
        }
    }
}


void doorbell_sound_start(doorbell_sound_handle_t handle)
{
    // 开启音频
    esp_codec_dev_sample_info_t fs = {
        .sample_rate = I2S_SAMPLE_RATE,
        .channel = I2S_CHANNELS,
        .bits_per_sample = I2S_SAMPLE_BITS,
        .channel_mask = ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0),
    };
    esp_codec_dev_open(handle->codec_dev, &fs);
    // 创建音频任务
    xTaskCreate(doorbell_sound_mic_task, "mic_task", 4096, handle, 5, &handle->mic_task_handle);
    xTaskCreate(doorbell_sound_speaker_task, "speaker_task", 4096, handle, 5, &handle->speaker_task_handle);
}

void doorbell_sound_stop(doorbell_sound_handle_t handle)
{
    // 停止任务
    vTaskDelete(handle->mic_task_handle);
    vTaskDelete(handle->speaker_task_handle);
    // 关闭设备
    esp_codec_dev_close(handle->codec_dev);
}


void doorbell_sound_deinit(doorbell_sound_handle_t handle)
{

}
